<template>
  <el-form label-width="100px">
    <!-- SPU 名称 -->
    <el-form-item label="SPU名称">
      <el-input placeholder="请输入 SPU 名称" v-model="SpuParams.spuName"></el-input>
    </el-form-item>
    <!-- SPU 品牌 -->
    <el-form-item label="SPU品牌">
      <el-select v-model="SpuParams.tmId">
        <el-option v-for="(item, index) in AllTradeMark" :key="item.id" :label="item.tmName" :value="item.id"></el-option>
      </el-select>
    </el-form-item>
    <!-- SPU描述 -->
    <el-form-item label="SPU描述">
      <el-input type="textarea" placeholder="请输入SPU描述" v-model="SpuParams.description"></el-input>
    </el-form-item>
    <!-- SPU图片 -->
    <el-form-item label="SPU图片">
      <!-- 
        v-model: fileList 展示默认图片
        action：上传图片的接口地址
        list-type:  展示图片的方法
        on-preview：点击图片预览图标的回调
        on-remove：点击删除图片图标的回调
        before-upload: 上传图片的回调
       -->
      <el-upload v-model:file-list="imgList" action="http://114.115.179.162:8022/prod-api/admin/product/fileUpload"
        list-type="picture-card" :on-preview="handlePictureCardPreview" :on-remove="handleRemove"
        :before-upload="handlerUpload">
        <el-icon>
          <Plus />
        </el-icon>
      </el-upload>

      <el-dialog v-model="(dialogVisible as boolean)">
        <img w-full :src="dialogImageUrl" alt="图片预览" style="width: 100%; height: 100%;" />
      </el-dialog>
    </el-form-item>
    <!-- SPU销售属性 -->
    <el-form-item label="SPU销售属性">
      <!-- 销售属性的下拉菜单 -->
      <el-select v-model="saleAttrIdAndValueName"
        :placeholder="unSelectSaleAttr.length ? `还存在${unSelectSaleAttr.length}个属性未选择` : '暂无属性可选择'">
        <!-- ${item.id}:${item.name} 以键值对的形式存储 value -->
        <el-option :value="`${item.id}:${item.name}`" v-for="(item, index) in unSelectSaleAttr" :key="item.id"
          :label="item.name"></el-option>
      </el-select>
      <el-button :disabled="saleAttrIdAndValueName ? false : true" type="primary" style="margin-left:10px" size="default"
        icon="Plus" @click="addSaleAttr">添加属性</el-button>
      <!-- 展示销售属性和属性值 -->
      <el-table border style="margin: 10px 0px;" :data="saleAttr">
        <!-- 序号 -->
        <el-table-column label="序号" type="index" width="80px" align="center"></el-table-column>
        <!-- 属性值名称 -->
        <el-table-column label="销售属性名称" width="120px" prop="saleAttrName"></el-table-column>
        <!-- 销售属性值 -->
        <el-table-column label="销售属性值">
          <template #="{ row, $index }">
            <!-- row 为当前已有的SPU销售属性对象 -->
            <!-- 属性值导入 tag 中 -->
            <el-tag style="margin:0px 5px" @close="row.spuSaleAttrValueList.splice(index, 1)"
              v-for="(item, index) in row.spuSaleAttrValueList" :key="row.id" class="mx-1" closable>
              {{ item.saleAttrValueName }}
            </el-tag>
            <!-- 添加某个属性值的输入框 -->
            <el-input @blur="toLook(row)" v-model="row.saleAttrValue" v-if="row.flag == true" placeholder="请你输入属性值"
              size="small" style="width:100px; margin-right: 5px;"></el-input>
            <!-- 添加某个属性值的按钮 -->
            <el-button @click="toEdit(row)" type="primary" size="small" icon="Plus"></el-button>
          </template>
        </el-table-column>
        <!-- 操作 -->
        <el-table-column label="操作" width="120px">
          <!-- 删除该行销售属性 -->
          <template #="{ row, $index }">
            <el-button type="primary" size="small" icon="Delete" @click="saleAttr.splice($index, 1)"></el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-form-item>
    <!-- 操作 保存和取消按钮 -->
    <el-form-item>
      <el-button :disabled="saleAttr.length > 0 ? false : true" type="primary" @click="save">保存</el-button>
      <el-button type="primary" @click="cancel">取消</el-button>
    </el-form-item>
  </el-form>
</template>

<script setup lang="ts">
import type { SpuData } from '@/api/product/spu/type'
import { ref, computed } from 'vue';
import { reqAllTradeMark, reqSpuImageList, reqSpuHasSaleAttr, reqAllSaleAttr, reqAddOrUpdateSpu } from '@/api/product/spu'
import type { SaleAttrValue, HasSaleAttr, SaleAttr, SpuImg, Trademark, AllTradeMark, SpuHasImg, SaleAttrResponseData, HasSaleAttrResponseData } from '@/api/product/spu/type';
import { ElMessage } from 'element-plus';
// 父给子传自定义事件
const $emit = defineEmits(['changeScene'])
// 点击取消按钮，通知父组件切换场景为0，展示已有SPU数据
const cancel = () => {
  // 这里的 update 执行了和更新一样的操作，但是没有保存更改数据
  $emit('changeScene', { flag: 0, params: 'update' })
}
//存储已有的SPU这些数据
const AllTradeMark = ref<Trademark[]>([]);
//商品图片
const imgList = ref<SpuImg[]>([]);
//已有的SPU销售属性
const saleAttr = ref<SaleAttr[]>([]);
//全部销售属性
const allSaleAttr = ref<HasSaleAttr[]>([]);
//存储已有的SPU对象（先按照新增的添加属性）
const SpuParams = ref<SpuData>({
  category3Id: "",//收集三级分类的ID
  spuName: "",//SPU的名字
  description: "",//SPU的描述
  tmId: '',//品牌的ID
  spuImageList: [],
  spuSaleAttrList: [],
});
// 控制图片放大对话框的显示与隐藏
const dialogVisible = ref<Boolean>(false);
// 存储预览（放大）图片的地址
const dialogImageUrl = ref<string>('');
// 收集 el-select 框选择的销售属性值键值对，即销售属性的ID和属性值
const saleAttrIdAndValueName = ref<string>('')
// 初始化SPU数据，以便父组件获取
const initHasSpuData = async (spu: SpuData) => {
  // spu: 父组件传递过来的已有的 SPU 对象[不完整]
  //存储已有的SPU对象,将来在模板中展示
  SpuParams.value = spu;
  //获取全部品牌的数据
  const result: AllTradeMark = await reqAllTradeMark();
  //获取某一个品牌旗下全部售卖商品的图片
  const result1: SpuHasImg = await reqSpuImageList((spu.id as number));
  //获取已有的SPU销售属性的数据
  const result2: SaleAttrResponseData = await reqSpuHasSaleAttr((spu.id as number));
  //获取整个项目全部SPU的销售属性
  const result3: HasSaleAttrResponseData = await reqAllSaleAttr();
  //存储全部品牌的数据
  AllTradeMark.value = result.data;
  //SPU对应商品图片
  // 通过 map 将属性名映射成为element-plus 需要的格式
  imgList.value = result1.data.map(item => {
    return {
      name: item.imgName,
      url: item.imgUrl
    }
  })
  //存储已有的SPU的销售属性
  saleAttr.value = result2.data;
  //存储全部的销售属性
  allSaleAttr.value = result3.data;
}

// 点击图片预览图标的回调
const handlePictureCardPreview = (file: any) => {
  // 存储预览（放大）图片
  dialogImageUrl.value = file.url;
  // 图片放大对话框弹出
  dialogVisible.value = true;
}
// 照片墙删除图片按钮的回调
const handleRemove = () => {
  // 删除图片按钮的内部逻辑已被element-plus封装好了，这个钩子只是用来定义其他回调功能的函数
}
// 上传图片的回调，约束文件的大小与类型
const handlerUpload = (file: any) => {
  if (file.type == 'image/png' || file.type == 'image/jpeg' || file.type == 'image/gif') {
    if (file.size / 1024 / 1024 < 3) {
      return true
    } else {
      ElMessage.error('上传的文件大小不能超过3M')
      return false
    }
  } else {
    ElMessage.error('上传的文件类型必须是PNG，JPG或者GIF')
    return false
  }
}
// 计算出当前SPU还未拥有的销售属性
const unSelectSaleAttr = computed(() => {
  // 过滤出目前不存在的销售属性 返回 true 就过滤出来
  const unSelectAttr = allSaleAttr.value.filter(item => {
    // 遍历每一个销售属性看是否存在
    return saleAttr.value.every(item1 => {
      return item.name != item1.saleAttrName
    })
  })
  return unSelectAttr
})
// 添加销售属性的方法
const addSaleAttr = () => {
  /**
   * 必须包含的三个参数
   * "baseSaleAttrId": number,
   * "saleAttrName": string,
   * "spuSaleAttrValueList": SpuSaleAttrValueList
   */
  const [baseSaleAttrId, saleAttrName] = saleAttrIdAndValueName.value.split(':')
  // 创建一个新的销售属性对象，来保存新增销售属性的数据
  let newSaleAttr: SaleAttr = {
    baseSaleAttrId,
    saleAttrName,
    spuSaleAttrValueList: []
  }
  // 追加到数组当中
  saleAttr.value.push(newSaleAttr)
  // 清空收集的数据
  saleAttrIdAndValueName.value = ''
}
// 添加属性值按钮的回调
const toEdit = (row: SaleAttr) => {
  // 点击添加（编辑）需要新增的属性值
  row.flag = true;
  row.saleAttrValue = ''
}
// 添加属性值表单失去焦点时的事件回调
const toLook = (row: SaleAttr) => {
  // 获取需要新增属性值的属性ID和属性值名字
  const { baseSaleAttrId, saleAttrValue } = row
  // 转换成后端服务器需要的属性值的形式
  let newSaleAttrValue: SaleAttrValue = {
    baseSaleAttrId,
    saleAttrValueName: (saleAttrValue as string)
  }
  // 非法情况判断
  if ((saleAttrValue as string).trim() == '') {
    ElMessage.error('属性值不能为空')
    return
  }
  // 判断属性值是否已经（在数组中）存在
  let repeat = row.spuSaleAttrValueList.find(item => {
    return item.saleAttrValueName == saleAttrValue
  })
  if (repeat) {
    ElMessage.error('属性值不能重复')
    return
  }
  // 追加新的属性值对象
  row.spuSaleAttrValueList.push(newSaleAttrValue)
  // 切换为非编辑（查看）模式
  row.flag = false
}
// 保存修改或者新增SPU的属性值
const save = async () => {
  // 收集照片墙的数据
  SpuParams.value.spuImageList = imgList.value.map((item: any) => {
    return {
      // 图片的名称
      imgName: item.name,
      // 如果原本有图片，则用响应回来的地址，否则使用本身 url
      imgUrl: (item.response && item.response.data) || item.url
    }
  })
  // 收集销售属性的数据
  SpuParams.value.spuSaleAttrList = saleAttr.value
  let result = await reqAddOrUpdateSpu(SpuParams.value)
  if (result.code == 200) {
    ElMessage({
      type: 'success',
      message: SpuParams.value.id ? '更新成功' : '添加成功'
    })
    $emit('changeScene', { flag: 0, params: SpuParams.value.id ? 'update' : 'add' })
  } else {
    ElMessage({
      type: 'error',
      message: SpuParams.value.id ? '更新失败' : '添加失败'
    })
  }
}
// 添加一个新的SPU的方法
const initAddSpu = async (c3Id: number | string) => {
  // 清空数据
  Object.assign(SpuParams.value, {
    category3Id: '', // 收集三级分类的ID
    spuName: '', // SPU的名字
    description: '',  // SPU的描述
    tmId: '',  // 品牌的ID
    spuImageList: [], // 照片墙
    spuSaleAttrList: []  // 销售属性
  })
  // 清空照片
  imgList.value = []
  // 清空销售属性
  saleAttr.value = []
  // 清空 el-select 框选择的销售属性值键值对，即销售属性的ID和属性值
  saleAttrIdAndValueName.value = ''
  // 存储三级分类ID
  SpuParams.value.category3Id = c3Id
  // 获取全部品牌的数据
  const result: AllTradeMark = await reqAllTradeMark()
  const result1: HasSaleAttrResponseData = await reqAllSaleAttr()
  // 存储数据
  AllTradeMark.value = result.data
  allSaleAttr.value = result1.data
}
// 对外暴露方法
defineExpose({ initHasSpuData, initAddSpu })
</script>

<style scoped></style>